package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.BusinessException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.*;
import org.dromara.system.domain.vo.*;
import org.dromara.system.enums.MachineConstant;
import org.dromara.system.enums.SysUserPointsRecordsEnum;
import org.dromara.system.enums.WithdrawalStatusEnum;
import org.dromara.system.mapper.SysUserWithdrawalMapper;
import org.dromara.system.service.*;
import org.dromara.system.service.impl.permission.PermissionBaseService;
import org.dromara.system.util.AlipayUtil;
import org.dromara.system.util.JsonUtil;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 提现记录Service业务层处理
 *
 * @author Lion Li
 * @date 2025-07-17
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserWithdrawalServiceImpl extends ServiceImpl<SysUserWithdrawalMapper, SysUserWithdrawal> implements ISysUserWithdrawalService {

    public static final String PREFIX = "TD";
    static final int TAG_LENGTH_BIT = 128;
    private static final String WECHAT_NOTIFY_URL = "https://td114-api.hbtuding.com/hy/system/userWithdrawal/wechatWithdrawalInitiation/callBack";
    private static final String URLSUFFIX = "/v3/fund-app/mch-transfer/transfer-bills";
    private final ISysUserPurseService sysUserPurseService;
    private final ISysUserWithdrawalPolicyService sysUserWithdrawalPolicyService;
    private final ISysUserPointsRecordsService sysUserPointsRecordsService;
    private final IZfbConfigService zfbConfigService;
    private final PermissionBaseService permissionBaseService;
    private final ISysUserService sysUserService;
    private final ISysUserCommonConfigService sysUserCommonConfigService;
    private final IWechatConfigService wechatConfigService;
    @Resource
    private AlipayUtil alipayUtil;

    public static synchronized String getOrderNo(int digit) {
        StringBuilder resultBuffer = new StringBuilder();
        resultBuffer.append(PREFIX)
            .append(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        Random random = new Random();
        for (int i = 0; i < digit; i++) {
            resultBuffer.append(random.nextInt(10));
        }
        return resultBuffer.toString();
    }

    public static void main(String[] args) {
        String orderNo = getOrderNo(10);
        System.out.println(orderNo);
    }

    /**
     * 查询提现记录
     *
     * @param id 主键
     * @return 提现记录
     */
    @Override
    public SysUserWithdrawalVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询提现记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 提现记录分页列表
     */
    @Override
    public TableDataInfo<SysUserWithdrawalVo> queryPageList(SysUserWithdrawalBo bo, PageQuery pageQuery) {
        BusinessException.isNull(bo.getStatusTag(), "statusTag标识不能为空！");
        permissionBaseService.assignPermission(bo);
        IPage<SysUserWithdrawalVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SysUserWithdrawalVo> list = baseMapper.findAll(page, bo);
        List<SysUserWithdrawalVo> records = list.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            records.forEach(t -> {
                t.setApprovalName(WithdrawalStatusEnum.findOne(t.getApprovalStatus()).getName());
            });
        }
        return TableDataInfo.build(list);
    }

    @Override
    public TableDataInfo<SysUserWithdrawalVo> listReception(SysUserWithdrawalBo bo, PageQuery pageQuery) {
        permissionBaseService.aloneAssignPermission(bo);
        IPage<SysUserWithdrawalVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SysUserWithdrawalVo> list = baseMapper.findAll(page, bo);
        List<SysUserWithdrawalVo> records = list.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            records.forEach(t -> {
                t.setApprovalName(WithdrawalStatusEnum.findOne(t.getApprovalStatus()).getName());
            });
        }
        BigDecimal withdrawalSummary = baseMapper.withdrawalSummary(bo);
        TableDataInfo<SysUserWithdrawalVo> build = TableDataInfo.build(list);
        build.setObj(withdrawalSummary);
        return build;
    }

    /**
     * 查询符合条件的提现记录列表
     *
     * @param bo 查询条件
     * @return 提现记录列表
     */
    @Override
    public List<SysUserWithdrawalVo> queryList(SysUserWithdrawalBo bo) {
        LambdaQueryWrapper<SysUserWithdrawal> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysUserWithdrawal> buildQueryWrapper(SysUserWithdrawalBo bo) {
        LambdaQueryWrapper<SysUserWithdrawal> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SysUserWithdrawal::getId);
        lqw.eq(bo.getUserId() != null, SysUserWithdrawal::getUserId, bo.getUserId());
        lqw.eq(bo.getAmount() != null, SysUserWithdrawal::getAmount, bo.getAmount());
        lqw.eq(bo.getReceivedAmount() != null, SysUserWithdrawal::getReceivedAmount, bo.getReceivedAmount());
        lqw.eq(bo.getIdentification() != null, SysUserWithdrawal::getIdentification, bo.getIdentification());
        lqw.eq(StringUtils.isNotBlank(bo.getAlipayAccount()), SysUserWithdrawal::getAlipayAccount, bo.getAlipayAccount());
        lqw.like(StringUtils.isNotBlank(bo.getAlipayUserName()), SysUserWithdrawal::getAlipayUserName, bo.getAlipayUserName());
        lqw.eq(StringUtils.isNotBlank(bo.getUserBankCardNumber()), SysUserWithdrawal::getUserBankCardNumber, bo.getUserBankCardNumber());
        lqw.eq(bo.getApprovalStatus() != null, SysUserWithdrawal::getApprovalStatus, bo.getApprovalStatus());
        lqw.eq(bo.getApprovalTime() != null, SysUserWithdrawal::getApprovalTime, bo.getApprovalTime());
        return lqw;
    }

    /**
     * 新增提现记录
     *
     * @param bo 提现记录
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SysUserWithdrawalBo bo) {
//        BusinessException.isTrue(Boolean.TRUE, "提现通道升级中，预计10小时后更新成功！");
        SysUserWithdrawal add = MapstructUtils.convert(bo, SysUserWithdrawal.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    @Override
    public Boolean wechatWithdrawalInitiation(SysUserWithdrawalBo bo) {
        log.info("wechatWithdrawalInitiation=={}", JSONUtil.toJsonStr(bo));
//        BusinessException.isTrue(StrUtil.isBlank(bo.getOpenId()), "用户OPENID不能为空！");
        SysUserWithdrawal entity = MapstructUtils.convert(bo, SysUserWithdrawal.class);
        BigDecimal amount = entity.getAmount();
        SysUserPurse sysUserPurse = sysUserPurseService.lambdaQuery().eq(SysUserPurse::getUserId, entity.getUserId()).one();
        BusinessException.isTrue(NumberUtil.isGreater(amount, sysUserPurse.getPoints()), "提现金额大于钱包余额！");
        //校验一级配置
        checkWithdrawal(entity);
        //计算到账金额
        SysUserWithdrawalPolicy sysUserWithdrawalPolicy = sysUserWithdrawalPolicyService.lambdaQuery().eq(SysUserWithdrawalPolicy::getUserId, entity.getUserId()).one();
        BigDecimal ratio = NumberUtil.sub(MachineConstant.NUMBER.ONE_BIGDECIMAL, NumberUtil.mul(sysUserWithdrawalPolicy.getRate(), MachineConstant.NUMBER.ZERO_POINT_ZERO_ONE));
        BigDecimal receivedAmount = NumberUtil.round(NumberUtil.sub(NumberUtil.mul(ratio, amount), sysUserWithdrawalPolicy.getMinus()), MachineConstant.NUMBER.TWO, RoundingMode.DOWN);
        BusinessException.isTrue(NumberUtil.isLessOrEqual(receivedAmount, BigDecimal.ZERO), "到账金额小于等于0！");
        String orderNo = getOrderNo(10);
        String insideNo = orderNo + RandomUtil.randomString(5);
        entity.setNo(orderNo);
        entity.setInsideNo(insideNo);
        entity.setReceivedAmount(receivedAmount);
        //钱包扣钱
        SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
            .userId(entity.getUserId())
            .type(SysUserPointsRecordsEnum.WITHDRAWAL_POINTS.getCode())
            .points(NumberUtil.mul(amount, MachineConstant.NUMBER.ONE_NEGATIVE))
            .build();
        sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
        SysUserVo sysUserVo = sysUserService.selectUserById(entity.getUserId());
        SysUserCommonConfig sysUserCommonConfig = sysUserCommonConfigService.lambdaQuery().eq(SysUserCommonConfig::getUserId, sysUserVo.getOneId()).one();
        Integer withdrawalWechatReview = sysUserCommonConfig.getWithdrawalWechatReview();
        if (ObjectUtil.equal(withdrawalWechatReview, MachineConstant.NUMBER.ZERO)) {
            //不需要审核
            entity.setApprovalStatus(WithdrawalStatusEnum.TO_BE_CLAIMED_WITHDRAWAL.getCode());
        } else {
            //需要审核
            entity.setApprovalStatus(WithdrawalStatusEnum.PENDING_APPROVAL.getCode());
        }
        baseMapper.insert(entity);
        return Boolean.TRUE;
    }

    public String wechatTransfer(WechatTransferBo bo) {
        WechatConfig wechatConfig = bo.getWechatConfig();
        Integer withdrawalAmount = Convert.toInt(NumberUtil.mul(bo.getReceivedAmount(), 100));
        long timestamp = System.currentTimeMillis() / 1000;
        String authType = "WECHATPAY2-SHA256-RSA2048";
        String nonceStr = WxPayKit.generateStr();
        //发起转账的商户号
        String mchId = wechatConfig.getMchId();
        //非对称加密，公钥证书的证书序列号
        String serialNo = wechatConfig.getGzhSerialNumber();
        //非对称加密的私钥  pem
        String privateKey = wechatConfig.getGzhPriKey();
        //转账业务信息
        JSONObject rootJSON = new JSONObject();
        rootJSON.put("appid", wechatConfig.getAppId());
        //商户单号，随机生成，但需要确保系统内唯一。
        rootJSON.put("out_bill_no", bo.getInsideNo());
        //转账场景id，默认值1000，代表：现金营销。可以到微信支付后台申请开通其他场景
        rootJSON.put("transfer_scene_id", "1000");
        rootJSON.put("openid", bo.getOpenId());
        //转账金额，单位：分
        rootJSON.put("transfer_amount", withdrawalAmount);
        rootJSON.put("transfer_remark", "分销");
        rootJSON.put("notify_url", WECHAT_NOTIFY_URL);
        //转账活动备注
        List<JSONObject> childList = getTransferSceneReportInfos();
        rootJSON.put("transfer_scene_report_infos", childList);
        String body = JSONUtil.toJsonStr(rootJSON);
        log.info("入参json:{}", body);
        // 调用IJPay框架的工具类生成待签名参数
        String buildSignMessage = PayKit.buildSignMessage(RequestMethodEnum.POST, URLSUFFIX, timestamp, nonceStr, body);
        //调用IJPay框架的工具类生成签名
        String signature = null;
        try {
            signature = PayKit.createSign(buildSignMessage, PayKit.getPrivateKey(privateKey));
        } catch (Exception e) {
            BusinessException.isTrue(Boolean.TRUE, "拉起微信转账失败！");
        }
        log.info("signature:{}", signature);
        // 调用IJPay框架的工具类，根据平台规则生成请求头 authorization
        String authorization = PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType);
        log.info("Authorization:{}", authorization);
        //完整的"商家转账到零钱"的请求链接
        String url = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills";
        //调用Hutool包的工具类发起post请求
        HttpResponse httpResponse = HttpRequest.post(url)
            .header("Authorization", authorization)
            .header("Accept", "application/json")
            .header("Wechatpay-Serial", wechatConfig.getGzhSerialNumber())
            .header("Content-Type", "application/json")
            .body(body)
            .execute();
        return httpResponse.body();
    }


    @Override
    public String wechatWithdrawalInitiationCall(HashMap<String, Object> map) {
        log.info("callBackForWithdrawal回调返回{}", JsonUtil.toJSONString(map));
        HashMap<String, Object> resultMap = new HashMap<>();
        try {
            Map<Object, Object> resource = JsonUtil.toMap(map.get("resource"));
            String decryptToString = decryptToString(Convert.toStr(resource.get("associated_data")).getBytes()
                , Convert.toStr(resource.get("nonce")).getBytes()
                , Convert.toStr(resource.get("ciphertext")));
            CallBackForWithdrawalVo callBackForWithdrawalVo = JsonUtil.toObject(decryptToString, CallBackForWithdrawalVo.class);
            log.info("微信转账订单号{},out_bill_no={}", callBackForWithdrawalVo.getOut_bill_no(), JsonUtil.toJSONString(callBackForWithdrawalVo));
            //查询该订单是否已经提现成功
            SysUserWithdrawal merWithdrawalRecords = lambdaQuery()
                .eq(SysUserWithdrawal::getInsideNo, callBackForWithdrawalVo.getOut_bill_no()).one();
            log.info("查询到的订单记录是{}", JsonUtil.toJSONString(merWithdrawalRecords));
            if (ObjectUtil.isNull(merWithdrawalRecords)
                || !ObjectUtil.equal(merWithdrawalRecords.getApprovalStatus(), WithdrawalStatusEnum.AWAITING_CONFIRMATION.getCode())) {
                resultMap.put("code", "SUCCESS");
                resultMap.put("message", "");
                return JsonUtil.toJSONString(resultMap);
            }
            //如果转账成功则扣掉用户钱包的钱
            if (StrUtil.equals(callBackForWithdrawalVo.getState(), "SUCCESS")) {
                //增加提现记录
                lambdaUpdate()
                    .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.SUCCESSFUL_WITHDRAWAL.getCode())
                    .eq(SysUserWithdrawal::getId, merWithdrawalRecords.getId())
                    .update();
            } else if (StrUtil.equals(callBackForWithdrawalVo.getState(), "FAIL")
                || StrUtil.equals(callBackForWithdrawalVo.getState(), "CANCELLED")) {
                lambdaUpdate()
                    .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.FAILED_WITHDRAWAL.getCode())
                    .eq(SysUserWithdrawal::getId, merWithdrawalRecords.getId())
                    .update();
                //给用户退钱
                SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
                    .userId(merWithdrawalRecords.getUserId())
                    .type(SysUserPointsRecordsEnum.WITHDRAWAL_REJECTED_POINTS.getCode())
                    .points(merWithdrawalRecords.getAmount())
                    .build();
                sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
            }
            resultMap.put("code", "SUCCESS");
            resultMap.put("message", "");
        } catch (Exception e) {
            log.info("微信转账失败，原因是{}", e.getMessage());
            resultMap.put("code", "FAILED");
            resultMap.put("message", "");
        }
        return JsonUtil.toJSONString(resultMap);
    }

    @Override
    public WeChatTransferToChangeVo claimWechatWithdrawal(ClaimWechatWithdrawalBo bo) {
//        BusinessException.isTrue(Boolean.TRUE, "提现通道升级中，预计10小时后更新成功！");

        SysUserWithdrawal merWithdrawalRecords = lambdaQuery()
            .eq(SysUserWithdrawal::getId, bo.getId()).one();
        BusinessException.isNull(merWithdrawalRecords, "提现订单号不存在");
        BusinessException.isTrue(ObjectUtil.notEqual(merWithdrawalRecords.getApprovalStatus(), WithdrawalStatusEnum.TO_BE_CLAIMED_WITHDRAWAL.getCode())
            , "订单不为待领取状态");
        SysUserVo sysUserVo = sysUserService.selectUserById(merWithdrawalRecords.getUserId());
        WechatConfig wechatConfig = wechatConfigService.lambdaQuery().eq(WechatConfig::getUserId, sysUserVo.getOneId()).one();
        BusinessException.isNull(wechatConfig, "代理商微信相关参数未配置！");
        String no = merWithdrawalRecords.getNo();
        //更换内部订单号
        String insideNo = no + RandomUtil.randomString(5);
        merWithdrawalRecords.setInsideNo(insideNo);
        lambdaUpdate()
            .set(SysUserWithdrawal::getInsideNo, insideNo)
            .eq(SysUserWithdrawal::getId, merWithdrawalRecords.getId())
            .update();
        WechatTransferBo transferBo = WechatTransferBo.builder()
            .wechatConfig(wechatConfig)
            .receivedAmount(merWithdrawalRecords.getReceivedAmount())
            .openId(bo.getOpenId())
            .orderNo(merWithdrawalRecords.getNo())
            .insideNo(merWithdrawalRecords.getInsideNo())
            .build();
        String resultBody = wechatTransfer(transferBo);
        if (StrUtil.contains(resultBody, "code")) {
            Map<Object, Object> map = JsonUtil.toMap(resultBody);
            String message = Convert.toStr(map.get("message"));
            BusinessException.isTrue(Boolean.TRUE, message);
        } else {
            WeChatTransferToChangeVo weChatTransferToChangeRspDTO = JSONUtil.toBean(resultBody, WeChatTransferToChangeVo.class);
            weChatTransferToChangeRspDTO.setAppId(wechatConfig.getAppId());
            weChatTransferToChangeRspDTO.setMchId(wechatConfig.getMchId());
            //修改状态
            lambdaUpdate()
                .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.AWAITING_CONFIRMATION.getCode())
                .eq(SysUserWithdrawal::getId, merWithdrawalRecords.getId())
                .update();
            return weChatTransferToChangeRspDTO;
        }
        return null;
    }

    @Override
    public List<HashMap<String, Object>> queryWithdrawalStatusEnums() {
        return Arrays.stream(WithdrawalStatusEnum.values())
            .map(t -> {
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("approvalStatus", t.getCode());
                hashMap.put("approvalStatusName", t.getName());
                return hashMap;
            }).collect(Collectors.toList());
    }

    @Override
    public TableDataInfo<SysUserWithdrawalVo> withdrawalPostingReview(PageQuery pageQuery) {
        IPage<SysUserWithdrawalVo> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
        IPage<SysUserWithdrawalVo> list = baseMapper.withdrawalPostingReview(page);
        return TableDataInfo.build(list);
    }

    @Override
    public void withdrawalRefund() {
        log.info("提现订单状态检测开始,驳回待确认到账状态订单");
        List<SysUserWithdrawal> list = lambdaQuery()
            .eq(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.AWAITING_CONFIRMATION.getCode())
            .le(SysUserWithdrawal::getUpdateTime, DateUtil.offsetMinute(new Date(), -120))
            .list();
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(t -> {
                lambdaUpdate()
                    .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.REJECT_WITHDRAWAL.getCode())
                    .eq(SysUserWithdrawal::getId, t.getId())
                    .update();
                //给用户退钱
                SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
                    .userId(t.getUserId())
                    .type(SysUserPointsRecordsEnum.WITHDRAWAL_REJECTED_POINTS.getCode())
                    .points(t.getAmount())
                    .remark("订单状态检测驳回")
                    .build();
                sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
            });
        }
    }

    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
        throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec key = new SecretKeySpec("fd92bed772bff671a17f56811f111731".getBytes(), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);
            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }


    private List<JSONObject> getTransferSceneReportInfos() {
        List<JSONObject> childList = new ArrayList<>();
        JSONObject childJSON1 = new JSONObject();
        //注意，注意，注意！！这个info_type的值不能改，只能写：活动名称，否则就会调用失败。
        childJSON1.put("info_type", "活动名称");
        childJSON1.put("info_content", "支付好礼");

        JSONObject childJSON2 = new JSONObject();
        //这个也一样。这个info_type的值也不能改，只能写：奖励说明，否则就会调用失败。
        childJSON2.put("info_type", "奖励说明");
        childJSON2.put("info_content", "支付好礼的奖励说明");
        childList.add(childJSON1);
        childList.add(childJSON2);
        return childList;
    }

    /**
     * 修改提现记录
     *
     * @param bo 提现记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SysUserWithdrawalBo bo) {
        SysUserWithdrawal update = MapstructUtils.convert(bo, SysUserWithdrawal.class);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    public void validEntityBeforeSave(SysUserWithdrawal entity) {
        BigDecimal amount = entity.getAmount();
        SysUserPurse sysUserPurse = sysUserPurseService.lambdaQuery().eq(SysUserPurse::getUserId, entity.getUserId()).one();
        BusinessException.isTrue(NumberUtil.isGreater(amount, sysUserPurse.getPoints()), "提现金额大于钱包余额！");
        //校验一级配置
        checkWithdrawal(entity);
        //0：支付宝 1：银行卡  2微信
        Integer identification = entity.getIdentification();
        if (ObjectUtil.equal(identification, MachineConstant.NUMBER.ZERO)) {
            BusinessException.isTrue(StrUtil.isBlank(entity.getAlipayAccount())
                || StrUtil.isBlank(entity.getAlipayUserName()), "支付宝账号，支付宝姓名不能为空！");
        } else if (ObjectUtil.equal(identification, MachineConstant.NUMBER.ONE)) {
            BusinessException.isTrue(Boolean.TRUE, "银行卡提现暂未开通！");
        } else if (ObjectUtil.equal(identification, MachineConstant.NUMBER.TWO)) {
            log.info("微信发起提现");
        } else {
            BusinessException.isTrue(Boolean.TRUE, "提现渠道错误！");
        }
        //计算到账金额
        SysUserWithdrawalPolicy sysUserWithdrawalPolicy = sysUserWithdrawalPolicyService.lambdaQuery().eq(SysUserWithdrawalPolicy::getUserId, entity.getUserId()).one();
        BigDecimal ratio = NumberUtil.sub(MachineConstant.NUMBER.ONE_BIGDECIMAL, NumberUtil.mul(sysUserWithdrawalPolicy.getRate(), MachineConstant.NUMBER.ZERO_POINT_ZERO_ONE));
        BigDecimal receivedAmount = NumberUtil.round(NumberUtil.sub(NumberUtil.mul(ratio, amount), sysUserWithdrawalPolicy.getMinus()), MachineConstant.NUMBER.TWO, RoundingMode.DOWN);
        BusinessException.isTrue(NumberUtil.isLessOrEqual(receivedAmount, BigDecimal.ZERO), "到账金额小于等于0！");
        //钱包扣钱
        SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
            .userId(entity.getUserId())
            .type(SysUserPointsRecordsEnum.WITHDRAWAL_POINTS.getCode())
            .points(NumberUtil.mul(amount, MachineConstant.NUMBER.ONE_NEGATIVE))
            .build();
        sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
        entity.setReceivedAmount(receivedAmount);
        String orderNo = getOrderNo(10);
        String insideNo = orderNo + RandomUtil.randomString(5);
        entity.setNo(orderNo);
        entity.setInsideNo(insideNo);
        entity.setApprovalStatus(WithdrawalStatusEnum.PENDING_APPROVAL.getCode());
    }

    public void checkWithdrawal(SysUserWithdrawal entity) {
        SysUserVo sysUserVo = sysUserService.selectUserById(entity.getUserId());
        Integer identification = entity.getIdentification();
        if (ObjectUtil.equal(identification, MachineConstant.NUMBER.TWO)
            && NumberUtil.isGreater(entity.getAmount(), Convert.toBigDecimal(200))) {
            BusinessException.isTrue(Boolean.TRUE, "微信提现不能超过200！");
            WechatConfig wechatConfig = wechatConfigService.lambdaQuery().eq(WechatConfig::getUserId, sysUserVo.getOneId()).one();
            BusinessException.isTrue(StrUtil.isBlank(wechatConfig.getMchId()), "代理商微信转账业务未开通！");
        }
        SysUserCommonConfig sysUserCommonConfig = sysUserCommonConfigService.lambdaQuery().eq(SysUserCommonConfig::getUserId, sysUserVo.getOneId()).one();
        //检查首笔提现
        List<SysUserWithdrawal> sysUserWithdrawals = lambdaQuery()
            .eq(SysUserWithdrawal::getUserId, entity.getUserId())
            .notIn(SysUserWithdrawal::getApprovalStatus, 3, 5).list();
        if (CollUtil.isEmpty(sysUserWithdrawals)) {
            //是首笔提现
            BigDecimal firstWithdrawalMin = sysUserCommonConfig.getFirstWithdrawalMin();
            if (ObjectUtil.isNotNull(firstWithdrawalMin)) {
                BusinessException.isTrue(NumberUtil.isLess(entity.getAmount(), firstWithdrawalMin), "首笔提现 最低金额为" + firstWithdrawalMin + "元！");
            }
        } else {
            //非首笔提现
            BigDecimal withdrawalMin = sysUserCommonConfig.getWithdrawalMin();
            if (ObjectUtil.isNotNull(withdrawalMin)) {
                BusinessException.isTrue(NumberUtil.isLess(entity.getAmount(), withdrawalMin)
                    , "非首笔提现 单笔提现最低金额为" + withdrawalMin + "元！");
            }
        }
        BigDecimal withdrawalMax = sysUserCommonConfig.getWithdrawalMax();
        if (ObjectUtil.isNotNull(withdrawalMax)) {
            BusinessException.isTrue(NumberUtil.isGreater(entity.getAmount(), withdrawalMax)
                , "单笔提现最高金额为" + withdrawalMax + "元！");
        }
        BigDecimal withdrawalMaxMonth = sysUserCommonConfig.getWithdrawalMaxMonth();
        if (ObjectUtil.isNotNull(withdrawalMaxMonth)) {
            //查询商户本月提现了多少钱
            List<SysUserWithdrawal> list = lambdaQuery()
                .eq(SysUserWithdrawal::getUserId, entity.getUserId())
                .notIn(SysUserWithdrawal::getApprovalStatus, 3, 5)
                .ge(SysUserWithdrawal::getCreateTime, DateUtil.beginOfMonth(DateUtil.date()))
                .le(SysUserWithdrawal::getCreateTime, DateUtil.endOfMonth(DateUtil.date())).list();
            BigDecimal totalAmount = list.stream()
                .map(SysUserWithdrawal::getAmount) // 提取amount字段
                .reduce(BigDecimal.ZERO, BigDecimal::add); // 求和
            //剩余可提现金额
            BigDecimal sub = NumberUtil.sub(withdrawalMaxMonth, totalAmount);
            BusinessException.isTrue(NumberUtil.isGreater(entity.getAmount(), sub),
                "单月最多能提现" + withdrawalMaxMonth + "元，您已提现" + totalAmount + "元！，本月剩余提现金额"
                    + NumberUtil.sub(withdrawalMaxMonth, totalAmount) + "元！");
        }
    }

    /**
     * 校验并批量删除提现记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public Boolean withdrawalApproval(WithdrawalApprovalBo bo) {
        SysUserWithdrawal sysUserWithdrawal = lambdaQuery()
            .eq(SysUserWithdrawal::getId, bo.getId()).one();
        BusinessException.isTrue(!ObjectUtil.equal(sysUserWithdrawal.getApprovalStatus(), WithdrawalStatusEnum.PENDING_APPROVAL.getCode()),
            "该订单不为待审核状态，请检查！");
        if (ObjectUtil.equal(bo.getStatus(), MachineConstant.NUMBER.ONE)) {
            //驳回 钱包加钱
            SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
                .userId(sysUserWithdrawal.getUserId())
                .type(SysUserPointsRecordsEnum.WITHDRAWAL_REJECTED_POINTS.getCode())
                .points(sysUserWithdrawal.getAmount())
                .build();
            sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
            lambdaUpdate()
                .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.REJECT_WITHDRAWAL.getCode())
                .set(SysUserWithdrawal::getApprovalTime, DateUtil.date())
                .eq(SysUserWithdrawal::getId, bo.getId()).update();
            return Boolean.TRUE;
        } else {
            //同意
            Integer identification = sysUserWithdrawal.getIdentification();
            if (ObjectUtil.equal(identification, MachineConstant.NUMBER.ZERO)) {
                AliPayVo aliPayVo = transferAliPay(sysUserWithdrawal);
                if (!StrUtil.equals(aliPayVo.getCode(), "10000")) {
                    BusinessException.isTrue(!StrUtil.equals(aliPayVo.getCode(), "10000")
                        , Convert.toStr(Convert.toStr(aliPayVo.getMsg(), "支付宝转账异常，请检查！")));
                }
                lambdaUpdate()
                    .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.SUCCESSFUL_WITHDRAWAL.getCode())
                    .set(SysUserWithdrawal::getApprovalTime, DateUtil.date())
                    .eq(SysUserWithdrawal::getId, bo.getId()).update();

            } else if (ObjectUtil.equal(identification, MachineConstant.NUMBER.ONE)) {
                //银行卡
                BusinessException.isTrue(Boolean.TRUE, "暂未开通银行卡转账！");
            } else if (ObjectUtil.equal(identification, MachineConstant.NUMBER.TWO)) {
                //微信
                lambdaUpdate()
                    .set(SysUserWithdrawal::getApprovalStatus, WithdrawalStatusEnum.TO_BE_CLAIMED_WITHDRAWAL.getCode())
                    .set(SysUserWithdrawal::getApprovalTime, DateUtil.date())
                    .eq(SysUserWithdrawal::getId, bo.getId()).update();
            } else {
                BusinessException.isTrue(Boolean.TRUE, "提现渠道异常！");
            }
        }
        return Boolean.TRUE;
    }


    public AliPayVo transferAliPay(SysUserWithdrawal sysUserWithdrawal) {
        AliPayVo aliPayVo = new AliPayVo();
        ZfbConfig zfbConfig = zfbConfigService.lambdaQuery().eq(ZfbConfig::getUserId, LoginHelper.getUserId()).one();
        BusinessException.isNull(zfbConfig, "未查询到您的支付宝配置！");
        AlipayClient alipayClient = null;
        try {
            alipayClient = alipayUtil.getAlipayClient(zfbConfig);
            AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
            AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
            model.setOutBizNo(getOrderNo(6));
            model.setTransAmount(String.valueOf(sysUserWithdrawal.getReceivedAmount()));
            model.setProductCode("TRANS_ACCOUNT_NO_PWD");
            model.setBizScene("DIRECT_TRANSFER");
            model.setOrderTitle("转账");
            //构建收款方
            Participant participant = new Participant();
            participant.setIdentity(sysUserWithdrawal.getAlipayAccount());
            participant.setIdentityType("ALIPAY_LOGON_ID");
            participant.setName(sysUserWithdrawal.getAlipayUserName());
            model.setPayeeInfo(participant);
            model.setRemark(sysUserWithdrawal.getNo() + "提现");
            request.setBizModel(model);
            log.info("支付宝转账参数={}", JsonUtil.toJSONString(model));
            AlipayFundTransUniTransferResponse response = null;
            response = alipayClient.certificateExecute(request);
            log.info("支付宝转账结果{}", response.getBody());
            String body = response.getBody();
            JSONObject entries = JSONUtil.parseObj(body);
            Map<Object, Object> data = JsonUtil.toMap(entries.get("alipay_fund_trans_uni_transfer_response"));
            String code = Convert.toStr(data.get("code"), "");
            if (ObjectUtil.equal(code, "10000")) {
                aliPayVo = AliPayVo.builder().code(code).msg("Success").build();
            } else {
                //转账失败
                String subMsg = Convert.toStr(data.get("sub_msg"), "支付宝转账异常，请检查！");
                aliPayVo = AliPayVo.builder().code(code).msg(subMsg).build();
            }
            return aliPayVo;
        } catch (Exception e) {
            throw new BusinessException(Convert.toStr(e.getMessage(), "支付宝转账异常，请检查!"));
        }

    }

}
